﻿using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Net;

namespace HashFoo.Core
{
    /// <summary>
    /// Defines the data provided from a web request that returns a string.
    /// </summary>
    public interface IWebResultString
    {
        /// <summary>
        /// The consumable data returned in the response.
        /// </summary>
        String Data { get; }

        /// <summary>
        /// The response meta data details.
        /// </summary>
        WebResultDetails Details { get; }
    }

    /// <summary>
    /// Wraps a web response as a string.
    /// </summary>
    public class WebResultString : WebResult<string>, IWebResultString
    {
        /// <summary>
        /// Wraps a web response as a string.
        /// </summary>
        /// <param name="response"></param>
        /// <param name="progressCallback"></param>
        public WebResultString(HttpWebResponse response, Action<ProgressEventArgs> progressCallback = null)
            : base(response)
        {
            using (var buffer = ReadResponse(response, progressCallback))
            using (var reader = new StreamReader(buffer))
            {
                var responseData = reader.ReadToEnd();
                Data = responseData;
            }
        }

        Stream ReadResponse(HttpWebResponse response, Action<ProgressEventArgs> progressCallback = null)
        {
            var safeProgressCallback = progressCallback ?? (args => { });
            const int readSize = 1024 * 8; // 8kb
            using (var networkStream = response.GetResponseStream())
            {
                var contentLength = (int)response.ContentLength;
                var length = contentLength > 0 ? contentLength : 0;
                var totalIsKnown = length != 0;

                var memoryBuffer = new MemoryStream(length);

                var buffer = new byte[readSize];
                int readCount;
                var currentPosition = 0;

                while ((readCount = networkStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    memoryBuffer.Write(buffer, 0, readCount);
                    currentPosition += readCount;

                    safeProgressCallback(new ProgressEventArgs
                    {
                        Current = currentPosition,
                        Percent = totalIsKnown ? (int)(Math.Round((float)currentPosition / length, 2) * 100) : 0,
                        Total = length,
                        TotalIsKnown = totalIsKnown
                    });
                }

                safeProgressCallback(new ProgressEventArgs
                {
                    Current = length,
                    Percent = 100,
                    Total = length,
                    TotalIsKnown = totalIsKnown
                });

                memoryBuffer.Seek(0, SeekOrigin.Begin);
                return memoryBuffer;
            }
        }
    }
}